home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / program / ixemlsrc.lha / ixemul / library / trap.s < prev    next >
Text File  |  1995-12-31  |  16KB  |  546 lines

  1. /*
  2.  *  This file is part of ixemul.library for the Amiga.
  3.  *  Copyright (C) 1991, 1992  Markus M. Wild
  4.  *  Portions Copyright (C) 1994 Rafael W. Luebbert
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *  $Id: trap.s,v 1.1 1994/06/19 15:17:35 rluebbert Exp $
  21.  *
  22.  *  $Log: trap.s,v $
  23. # Revision 1.1  1994/06/19  15:17:35  rluebbert
  24. # Initial revision
  25. #
  26.  */
  27.  
  28.     .globl    _trap_00
  29.     .globl    _restore_00
  30.     .globl    _sup00_do_sigreturn
  31.     .globl    _sup00_do_sigreturn_ssp
  32.     .globl    _trap_20
  33.     .globl    _restore_20
  34.     .globl    _sup20_do_sigreturn
  35.     .globl    _sup20_do_sigreturn_ssp
  36.     .globl    _supervisor
  37.     .globl    _do_sigreturn
  38.     .globl    _launch_glue
  39.     .globl    _addupc
  40.     .globl    _resetfpu
  41.  
  42.     | Note that stopped process handling is currently only implemented
  43.     | for >= 68020 CPUs!
  44.  
  45.     | If this is non-zero, we return from the traphandler to this
  46.     | address (in user mode) rather than the address that caused
  47.     | the trap in the first place.  This is used to implement
  48.     | stopped processes for debugging.
  49. .comm _stop_process,4
  50.  
  51.     | When the process is to resume from the SSTOP state, we restore
  52.     | the task state and RTE back using the address and status
  53.     | register stored here.  (Actually, this info is immediately copied
  54.     | in the function that handles the stopped process; otherwise only
  55.     | one process at a time could be in the SSTOP state).
  56. .comm _stop_rte_sp,4
  57. .comm _stop_rte_pc,4
  58. .comm _stop_rte_sr,4
  59.  
  60. #undef DEBUG
  61.  
  62.     | This is the trap processing function for the mc68000.
  63.     | Things are quite easy here, just save the general purpose registers
  64.     | and the pc/sr combo, call trap(), then restore the previous
  65.     | context and return
  66. _trap_00:
  67.     movel    a5,sp@-        | need a scratch register
  68.     movel    usp,a5        | get usp
  69.     moveml    d0-d7/a0-a6,a5@-| store registers on usp
  70.     movel    sp@+,a5@(0x34)    | insert the saved a5 into the saveset
  71.     movel    sp@+,d2        | remember trapnumber
  72.     movew    sp@+,a5@-    | copy SR
  73.     movel    sp@+,a0        | remember and
  74.     movel    a0,a5@-        | copy offending PC
  75.  
  76.     |
  77.     | pass return address and ssp-value on userstack
  78.     | This happens for the same reason as we have a glue_launch entry.
  79.     | trap cleans up these 8 bytes on the user stack itself
  80.     movel    sp,a5@-
  81.     movel    #_restore_00,a5@-
  82.     movel    a5,usp        | and remember current value of usp (a5)
  83.  
  84.     | fine, now process this trap. This might (doesn't have to) push
  85.     | additional frames. If not, we just return where the exception 
  86.     | took place (and probably will again...)
  87.  
  88.     movel    a0,sp@-        | pass offending address (don't know more about it)
  89.     addl    d2,d2        | convert the passed trap number into a fake
  90.     addl    d2,d2        | 68020 frame format word
  91.     movel    d2,sp@-        | and pass it as argument
  92.     jsr    _trap        | to the higher level C trap 
  93.     lea    sp@(8),sp    | processor
  94.  
  95. _restore_00:
  96.     movel    usp,a5        | get usp
  97.     lea    a5@(0x42),a1    | skip over the now no longer needed frame
  98.     movel    a1,usp        | -> 15 registers, one PC and one SR
  99.     
  100.     | set up the original supervisor stack frame
  101.     movel    a5@+,sp@-    | PC
  102.     movew    a5@+,sp@-    | SR
  103.     moveml    a5@,d0-d7/a0-a6    | and the other cpu registers
  104.     rte
  105.  
  106.  
  107.  
  108.     | This is the trap processor for the mc68020 and above, paired with
  109.     | an fpu (don't *need* an fpu though).
  110.     | What is done: start is same as with 68000, but then the complete
  111.     | additional exception frame is saved on the usp, together with the
  112.     | fpu state. Then trap() is called, and then the previous context
  113.     | is restored (involves copying back the frame from the usp over to the ssp)
  114. _trap_20:
  115.     movel    a5,sp@        | nuke the trap number, we use the frame format word
  116.     movel    usp,a5        | get usp
  117.     moveml    d0-d7/a0-a6,a5@-| store registers on usp
  118.     movel    sp@+,a5@(0x34)    | insert the saved a5 into the saveset
  119.     movew    sp@+,a5@-    | copy SR
  120.     movel    sp@+,d2        | remember and
  121.     movel    d2,a5@-        | copy (offending?) PC
  122.  
  123.     | find out more about the frame (according to the MC68030 user manual)
  124.     clrl    d1
  125.     movew    sp@+,d1        | remember frame format word
  126.     movew    d1,d0
  127.     andw    #0xf000,d0
  128.     beq    Lfmt_S0        | S0
  129.     cmpw    #0x1000,d0
  130.     beq    Lfmt_S1        | S1 this (interrupt) frame shouldn't be here...
  131.     cmpw    #0x2000,d0
  132.     beq    Lfmt_S2        | CHK{2},cpTRAPcc,TRAPV,Trace,Div0,MMUcfg,cp post instr
  133.     cmpw    #0x9000,d0
  134.     beq    Lfmt_S9        | cp mid instr,main det prot viol,int during cp instr
  135.     cmpw    #0xa000,d0
  136.     beq    Lfmt_SA_SB    | address or bus error, short and long frame
  137.     cmpw    #0xb000,d0
  138.     bne    Lfmt_S0        | ??? frame, this will probably not fully cleanup sp..
  139.  
  140. Lfmt_SA_SB:
  141.     | this part (upto Lbe10) inspired by locore.s in sys/hp300/ of BSD4.3-reno
  142.     movew    sp@(2),d0    | grab SSW for fault processing
  143.     btst    #12,d0        | RB set?
  144.     beq    LbeX0        | no, test RC
  145.     bset    #14,d0        | yes, must set FB
  146.     movew    d0,sp@(2)    | for hardware too
  147. LbeX0:
  148.     btst    #13,d0        | RC set?
  149.     beq    LbeX1        | no, skip
  150.     bset    #15,d0        | yes, must set FC
  151.     movew    d0,sp@(2)    | for hardware too
  152. LbeX1:
  153.     btst    #8,d0        | data fault?
  154.     beq    Lbe0        | no, check for hard cases
  155.     movel    sp@(8),d2    | fault address is as given in frame
  156.     bra    Lbe10        | thats it
  157. Lbe0:
  158.     btst    #12,d1        | long (type B) stack frame?
  159.     bne    Lbe4        | yes, go handle
  160.     btst    #14,d0        | no, can use saved PC. FB set?
  161.     beq    Lbe3        | no, try FC
  162.     addql    #4,d2        | yes, adjust address
  163.     bra    Lbe10        | done
  164. Lbe3:
  165.     btst    #15,d0        | FC set?
  166.     beq    Lbe10        | no, done
  167.     addql    #2,d2        | yes, adjust address
  168.     bra    Lbe10        | done
  169. Lbe4:
  170.     movel    sp@(28),d2    | long format, use stage B address
  171.     btst    #15,d0        | FC set?
  172.     beq    Lbe10        | no, all done
  173.     subql    #2,d2        | yes, adjust address
  174. Lbe10:
  175.  
  176.     | now move the frame over to the usp (6/21 longwords remain)
  177.     
  178.     moveml    sp@+,d3-d7/a0    | may trash as many registers as I like, I saved
  179.     moveml    d3-d7/a0,a5@-    | them already ;-) First copy 6 longs
  180.  
  181.     btst    #12,d1        | long (type B) stack frame?
  182.     beq    Lfmt_S0        | nope, done
  183.  
  184.     moveml    sp@+,d3-d7/a0-a2 | first copy 8 longs
  185.     moveml    d3-d7/a0-a2,a5@-
  186.     moveml    sp@+,d3-d7/a0-a1 | plus 7 gives 15, plus already stored 6 is 21
  187.     moveml    d3-d7/a0-a1,a5@-
  188.     bra    Lfmt_S0        | finito
  189.  
  190. Lfmt_S9:
  191.     movel    sp@+,a5@-    | S9 is an S2 plus 4 internal (word length) registers
  192.     movel    sp@+,a5@-    | so store those registers, and fall into S2
  193.  
  194. Lfmt_S2:
  195.     movel    sp@+,d2        | S2 contains the offending instruction address
  196.                 | and the frame format word
  197.     movel    d2,a5@-        | we have the offending instruction address here
  198.  
  199.     | fall into
  200.  
  201. Lfmt_S0:
  202. Lfmt_S1:
  203.     movew    d1,a5@-        | and as the last thing store the frame format word
  204.  
  205.     |
  206.     | now lets look at the fpu, if there is an fpu in the system
  207.     |
  208.     
  209.     btst    #4,(4)@(0x129)    | is AFB_68881 set in SysBase->AttnFlags ??
  210.     beq    Lno_fpu
  211.     fsave    a5@-        | dump the fpu state onto the usp
  212.     moveb    a5@,d0        | and get the fpu state identifier
  213.     beq    Lno_fpu        | null frame?
  214.  
  215.     clrl    d0
  216.     moveb    a5@(1),d0    | load state frame size
  217.     bset    #3,a5@(d0)    | set bit 27 of BIU
  218.  
  219.     fmovemx    fp0-fp7,a5@-        | push the fpu data registers and
  220.     fmoveml    fpcr/fpsr/fpi,a5@-    | fpu control registers
  221.  
  222.     movew    #-1,a5@-    | mark that there is fpu stuff on the stack
  223. Lno_fpu:
  224.  
  225.     |
  226.     | pass return address and ssp-value on userstack
  227.     | This happens for the same reason as we have a glue_launch entry.
  228.     | trap cleans up these 8 bytes on the user stack itself
  229.     movel    sp,a5@-
  230.     movel    #_restore_20,a5@-
  231.  
  232.     movel    a5,usp        | set the new value of the usp
  233.  
  234.     | that's it, phew.. now process this frame, and perhaps throw some
  235.     | frames on it as well to deal with the signal
  236.     
  237.     movel    d2,sp@-        | pass offending PC
  238.     movel    d1,sp@-        | pass frame format word
  239.     clrl    _stop_process    | clear old request to stop process
  240.     jsr    _trap        | do distribution in C ;-)
  241.     lea    sp@(8),sp
  242.  
  243. _restore_20:
  244.     |
  245.     | restore the saved stack frame from the usp, and copy the necessary
  246.     | parts over to the ssp
  247.     |
  248.  
  249.     movel    usp,a5
  250.     
  251.     | first deal with fpu stuff, if there's an fpu
  252.  
  253.     btst    #4,(4)@(0x129)    | is AFB_68881 set in SysBase->AttnFlags ??
  254.     beq    Lno_fpu2
  255.     tstb    a5@
  256.     beq    Lrst_fpu_frame    | there's only the null frame, go and restore it
  257.  
  258.     lea    a5@(2),a5    | skip fpu indicator
  259.     fmoveml    a5@+,fpcr/fpsr/fpi    | restore fpu control and
  260.     fmovemx    a5@+,fp0-fp7        | fpu data registers
  261.     
  262. Lrst_fpu_frame:
  263.     frestore a5@+        | and restore the internal fpu state
  264. Lno_fpu2:
  265.     movew    a5@+,d1        | get frame format word
  266.     movew    d1,d0
  267.     andw    #0xf000,d0
  268.     beq    Lrfmt_S0    | S0
  269.     cmpw    #0x1000,d0
  270.     beq    Lrfmt_S1    | S1
  271.     cmpw    #0x2000,d0
  272.     beq    Lrfmt_S2    | S2
  273.     cmpw    #0x9000,d0
  274.     beq    Lrfmt_S9    | S9
  275.     cmpw    #0xa000,d0
  276.     beq    Lrfmt_SA    | SA
  277.     cmpw    #0xb000,d0
  278.     bne    Lrfmt_S0    | ??? frame
  279.  
  280. Lrfmt_SB:
  281.     moveml    a5@+,d3-d7/a0-a2
  282.     moveml    d3-d7/a0-a2,sp@-
  283.     moveml    a5@+,d3-d7/a0-a1
  284.     moveml    d3-d7/a0-a1,sp@- | copy 15 longs
  285.  
  286. Lrfmt_SA:
  287.     movel    a5@+,sp@-    | copy  3 longs
  288.     movel    a5@+,sp@-
  289.     movel    a5@+,sp@-
  290.     
  291. Lrfmt_S9:
  292.     movel    a5@+,sp@-    | copy  2 longs
  293.     movel    a5@+,sp@-
  294.  
  295. Lrfmt_S2:
  296.     movel    a5@+,sp@-    | copy  1 long
  297.  
  298. Lrfmt_S1:
  299. Lrfmt_S0:
  300.     movew    d1,sp@-        | insert frame format word
  301.     tstl    _stop_process    | is this process going to be stopped?
  302.     beq    Ldont_stop    | no
  303.  
  304.     movel    a5@+,_stop_rte_pc    | yes, stash away the return pc
  305.     movel    #stop_process_glue,sp@-    | we RTE to the stopped process handler
  306.     movew    a5@,_stop_rte_sr    | don't forget the status register
  307.     movew    a5@+,sp@-
  308.     bra    Lstop_over
  309.  
  310. Ldont_stop:
  311.     movel    a5@+,sp@-    | copy PC
  312.     movew    a5@+,sp@-    | and SR
  313.     
  314. Lstop_over:
  315.     lea    a5@(0x3c),a1    | skip the rest of the frame
  316.     movel    a1,usp        | 0x3c -> 15 registers
  317.     
  318.     moveml    a5@,d0-d7/a0-a6    | restore the cpu registers
  319.     rte            | that's it (finally) .. 
  320.  
  321. stop_process_glue:
  322.     | This routine is called in usermode and we are running in the
  323.     | context of the stopped exec.library Task/Process.  Stash away
  324.     |  the registers and call the C handler.
  325.     movel    sp,_stop_rte_sp
  326.     movel    _stop_rte_sr,sp@-
  327.     movel    _stop_rte_pc,sp@-
  328.     moveml    d0-d7/a0-a7,sp@-
  329.     movel    _stop_rte_sp,sp@(0x3c) | insert real usp into the saveset
  330.     |
  331.     movel    sp,sp@-        | give address of registers as argument
  332.     movel    _stop_process,a0
  333.     jsr    a0@
  334.     lea    sp@(4),sp    | pop argument
  335.     |
  336.     | Time to resume the task.  We must restore the state of the task
  337.     | completely, including the status register (which might have got
  338.     | the trace bit set now).  The only way to do this is using the RTE
  339.     | instruction, which is privileged.  Thus, we must enter supervisor
  340.     | mode temporarily to be able to execute the RTE.
  341.     |
  342.     movel    #resume_task,a5    | where to go in supervisor mode
  343.     movel  4:w,a6        | SysBase
  344.     jmp    a6@(-0x1e)    | exec.library Supervisor() call
  345.  
  346. resume_task:
  347.     lea    sp@(6),sp    | Clean up supervisor stack, we do not want to
  348.                 | RTE to the location after the Supervisor() call.
  349.     movel    usp,a6        | get usp
  350.     movel    a6@(0x3c),a0    | restore usp for the program
  351.     movel    a0,usp
  352.     moveml    a6@,d0-d7/a0-a6    | don't post-increment a6; no need to pop the stack,
  353.                 | usp is already set
  354.     movel    _stop_rte_pc,sp@-
  355.     movew    _stop_rte_sr,sp@-
  356.     rte
  357.  
  358.  
  359.     |
  360.     | jump to the given argument in supervisor mode
  361.     | does NOT return
  362.     |
  363. _supervisor:
  364.     movel    sp@(4),a5    | where to go in supervisor
  365.     movel    sp@(8),sp@-    | with this usp
  366.     movel    a6,sp@-
  367.     movel    4:w,a6
  368.     jmp    a6@(-0x1e)    | do it (Supervisor() system call)
  369.  
  370.  
  371.     |
  372.     | restore signal context
  373.     | argument comes in usp
  374.     |
  375.     | mc68020 entry
  376. _sup20_do_sigreturn_ssp:    | entry via jsr from supervisor mode
  377.     movel    sp@(4),sp    | set ssp
  378. _sup20_do_sigreturn:
  379.     lea    sp@(-8),sp    | make room for an exception frame
  380.     movew    #0x20,sp@(6)    | fake format word
  381.     bra    fromsup_sigreturn
  382.  
  383.     | mc68000 entry
  384. _sup00_do_sigreturn_ssp:
  385.     movel    sp@(4),sp    | set ssp
  386. _sup00_do_sigreturn:
  387.     lea    sp@(-6),sp    | make room for an exception frame
  388.  
  389. fromsup_sigreturn:
  390.     moveml    d0/d1/a0/a1,sp@-
  391.  
  392.     movel    usp,a0        | get signal context
  393.     bra    resume_sigreturn
  394.  
  395.     | fall into _do_sigreturn
  396.  
  397.  
  398.     | Supervisor() entry (already comes on exception frame)
  399. _do_sigreturn:
  400.     | make the sigreturn() function preserve all registers
  401.     moveml    d0/d1/a0/a1,sp@-
  402.  
  403.     movel    usp,a0        | get signal context
  404.     movel    a0@+,a6        | restore the trashed a6 register
  405.     movel    a0@,a0
  406.  
  407. resume_sigreturn:
  408.  
  409.  
  410.     movel    4:w,a1        | SysBase
  411.     movel    a1,d1        | remember for later setting of sc_ap
  412.     movel    a1@(0x114),a1    | ThisTask
  413.     movel    a1@(0x2e),a1    | TrapData -> (struct user *)
  414.     
  415.     | ok, now a0:sc, a1:u
  416.  
  417.     | offsets are determined by create_defines
  418. #include "ix_internals.h"
  419.     movel    a0@+,a1@(U_ONSTACK_OFFSET)    | u.u_onstack = sc->sc_onstack
  420.     movel    a0@+,a1@(P_SIGMASK_OFFSET)    | u.p_sigmask = sc->sc_mask
  421.     movel    a0@+,a1        | usp = sc->sc_sp
  422.     movel    a1,usp
  423.     movel    a0@+,a5        | fp  = sc->sc_fp
  424.  
  425.  
  426.  
  427.     movel    d1,a1        | get back SysBase
  428.     movel    a1@(0x114),a1    | ThisTask
  429.     movel    a0@,a1@(0x0e)    | store Flags,State,IDNestCnt,TDNestCnt
  430.     movel    d1,a1
  431.     lea    a0@(2),a0    | skip unused part of sc_ap
  432.     movew    a0@+,d1        | get IDNestCnt and TDNestCnt
  433.     movew    d1,a1@(0x126)    | store them in SysBase
  434.     tstb    a1@(0x126)
  435.     bmi    Lenable
  436. Ldisabled:
  437.     movew    #0x4000,0xdff09a    | disable interrupts
  438.     bra    Lint_twiddle
  439. Lenable:
  440.     movew    #0xc000,0xdff09a    | enable interrupts
  441. Lint_twiddle:
  442.     | set pc and sr in current exception frame
  443.     movel    a0@+,sp@(2+4*4)    | set PC
  444.     movew    a0@(2),sp@(4*4)    | and SR
  445.     moveml    sp@+,d0/d1/a0/a1
  446.     rte
  447.  
  448.  
  449.  
  450.     |
  451.     | launch_glue is used to invoke the sig_launch handler. We have to care to
  452.     | clean the supervisor stack, if we should call a signal handler from
  453.     | the launch handler.
  454.     | The bad thing is, that doing this right needs information on how 
  455.     | the tc_Launch entry is called from the OS. Thus I pass two parameters
  456.     | on the user stack, the value of the `virgin' ssp and the value of
  457.     | a4, which happens to contain the address of the context restore
  458.     | function.
  459.     | It is assumed, that tc_Launch is called via 
  460.     | ... jsr sub
  461.     | ...
  462.     | sub:jsr tc_Launch
  463.     | Thus we have to backup the sp by two jsr's, which is 8.
  464.  
  465. _launch_glue:
  466.     movel    4:w,a0
  467.     movel    a0@(0x114),a0    | tid = SysBase->ThisTask
  468.     movel    a0@(0x36),a0    | usp isn't setup correctly, do it now from tc_SPReg
  469.     movel    sp,a0@-
  470.     addl    #8,a0@
  471.     movel    a4,a0@-
  472.     movel    a0,usp
  473.     
  474.     jsr    _sig_launch    | sig_launch `(void *pc_ret, *ssp_ret)' (`' on usp)
  475.  
  476.     | sig_launch() already corrects the usp to pop those two arguments
  477.     rts
  478.  
  479.  
  480.  
  481. /*
  482.  * update profiling information for the user
  483.  * addupc(pc, &u.u_prof, ticks)
  484.  */
  485. _addupc:
  486.     movl    a2,sp@-            | scratch register
  487.     movl    sp@(12),a2        | get &u.u_prof
  488.     movl    sp@(8),d0        | get user pc
  489.     subl    a2@(8),d0        | pc -= pr->pr_off
  490.     jlt    Lauexit            | less than 0, skip it
  491.     movl    a2@(12),d1        | get pr->pr_scale
  492.     lsrl    #1,d0            | pc /= 2
  493.     lsrl    #1,d1            | scale /= 2
  494.  
  495.     moveml    d0/d1,sp@-
  496.     jbsr    ___mulsi3
  497.     lea    sp@(8),sp
  498.  
  499.     moveq    #14,d1
  500.     lsrl    d1,d0            | pc >>= 14
  501.     bclr    #0,d0            | pc &= ~1
  502.     cmpl    a2@(4),d0        | too big for buffer?
  503.     jge    Lauexit            | yes, screw it
  504.     addl    a2@,d0            | no, add base
  505.  
  506.     movel    d0,a0
  507.     movew    a0@,d0
  508.  
  509.     addw    sp@(18),d0        | add tick to current value
  510.  
  511.     movew    d0,a0@
  512.  
  513. Lauexit:
  514.     movl    sp@+,a2            | restore scratch reg
  515.     rts
  516.  
  517. _resetfpu:
  518.     moveml    a5/a6,sp@-
  519.     lea    Lreset_fpu,a5
  520.     movel    4:w,a6
  521.     jsr    a6@(-30)        | Supervisor()
  522.     bra    Lafter_reset_fpu
  523.  
  524. Lreset_fpu:
  525.     btst    #7,(4)@(0x129)    | is AFB_68060 set in SysBase->AttnFlags ??
  526.     beq    Lno_060fpu      | found 060 and put 2 more longs on stack
  527.     clrl    sp@-            | prepare 060 fpu null state frame
  528.     clrl    sp@-            | needs 2 additional longs on stack
  529.  
  530. Lno_060fpu:
  531.     clrl    sp@-
  532.     frestore sp@+
  533.  
  534.     | Note that after using frestore with a null state frame we have
  535.     | to set up the control register to restore rounding to truncation
  536.     | rather than round-to-nearest, as required by the ANSI C standard.
  537.  
  538.         moveq    #72,d0
  539.         addl     d0,d0
  540.         fmovel   d0,fpcr
  541.     rte
  542.  
  543. Lafter_reset_fpu:
  544.     moveml    sp@+,a5/a6
  545.     rts
  546.